/**
 * Categoria.java
 * @author Paulo Chang, Carnet 11076
 * @author Oscar Castañeda, Carnet 11086
 * @author Francisco Martínez, Carnet 11096
 * @since 27/10/2011
 * Modificado por última vez el 06/11/2011.
 * Descripción: Clase que representa a una categoría y permite llevar control
 * sobre ellas.
 */


import java.sql.ResultSet;
import java.util.ArrayList;


public class Categoria {

    
    //Atributos
    
    //Titulo de la categoría en MySQL
    private String tituloBD;
    //Titulo de la categoría para el usuario
    private String tituloUser;
    //Lista con los nombres de los campos en MySQL
    private ArrayList<String> camposBD;
    //Lista con los nombres de los campos para el usuario, en correspondencia con lista anterior.
    private ArrayList<String> camposUser;
    //Conexion a base de datos
    private ConexionBD conexion;
    //Número de datos obligatorios, contando el id.
    private int numCamposObligatorios;
    //Indica si la categoría ha sido creada correctamente o  no.
    private boolean fine;

    
    /**
     * Permite crear una nueva categoría.
     * @param conexion ConexionBD sobre la cual se esta basando el programa.
     * @param tituloIngresadoPorUsuario String con el titulo ingresado por el usuario para llamar a la categoría.
     * @param camposObligatorios Lista de Strings con los nombres de los campos obligatorios para la categoría.
     */
    public Categoria(ConexionBD conexion, String tituloIngresadoPorUsuario, String... camposObligatorios) {
        this.conexion = conexion;
        tituloUser = tituloIngresadoPorUsuario;
        tituloBD = adaptarParaBD(tituloUser);
        numCamposObligatorios = camposObligatorios.length;
        camposBD = new ArrayList();
        camposUser = new ArrayList();
        if (!conexion.existeTabla(tituloBD)) {
            //Creación inicial de la categoría, en caso de que esta no exista.
            for (String nombreCampo : camposObligatorios) {
                camposUser.add(nombreCampo);
                camposBD.add(adaptarParaBD(nombreCampo));
            }
            boolean creado = conexion.crearTablaCategoria(tituloBD, camposBD);
            if (creado) {
                fine = true;
            } else {
                fine = false;
            }
        } else {
            //Si ya existe la categoría, se recuperan sus datos.
            ResultSet informacion = conexion.datosDeTabla(tituloBD);
            Object[] nombresCamposBD = GeneradorModeloTabla.titulosColumnas(informacion);
            for (Object campoBD : nombresCamposBD) {
                String titulo = (String) campoBD;
                camposBD.add(titulo);
                camposUser.add(adaptarParaUsuario(titulo));
            }
        }
    }

    /**
     * Devuelve la lista de los nombres de campos para el usuario.
     * @return Object[] Con el nombre de los campos adaptados para el usuario.
     */
    public Object[] getCamposUser() {
        return camposUser.toArray();
    }

    /**
     * Devuelve la información en la base de datos relacionada a la categoría.
     * @return ResultSet con la información correspondiente a la categoría en la base de datos MySQL.
     */
    public ResultSet getResultSet() {
        return conexion.datosDeTabla(tituloBD);
    }

    /**
     * Permite agregar un nuevo campo en la tabla en MySQL correspondiente
     * a esta categoría.
     * @param nombreCampoIngresado Nombre para la nueva tabla de usuario, el cual aún debe de ser
     * adaptado para la base de datos.
     */
    public void crearCampo(String nombreCampoIngresado) {
        String nombreAdaptado = adaptarParaBD(nombreCampoIngresado);
        boolean agregado = conexion.agregarColumna(tituloBD, nombreAdaptado);
        if (agregado) {
            camposUser.add(nombreCampoIngresado);
            camposBD.add(nombreAdaptado);
        } else {
            javax.swing.JOptionPane.showMessageDialog(null, "<html>No se ha podido crear campo.<br> Trate con un nombre diferente.</html>");
        }
    }

    /**
     * Permite borrar un campo en esta categoría, siempre y cuando este no sea un 
     * campo obligatorio para esta misma.
     * @param columna int con el número de columna en el cual se encuentra el campo a eliminar.
     */
    public void borrarCampo(int columna) {
        if (columna >= numCamposObligatorios) {
            String nombre = camposUser.get(columna);
            int opcion = javax.swing.JOptionPane.showConfirmDialog(null, "¿Desea borrar el campo " + nombre + "?");
            if (opcion == 0) {
                conexion.eliminarColumna(tituloBD, nombre);
                camposUser.remove(nombre);
                camposBD.remove(adaptarParaUsuario(nombre));
            }
        } else {
            javax.swing.JOptionPane.showMessageDialog(null, "No se puede borrar este campo.");
        }
    }

    /**
     * Permite agregar un nuevo elemento a esta categoría.
     * @param titulo String con el título para el elemento creado.
     * @param contrasena String con la contraseña para el elemento creado.
     */
    public void agregarElemento(String titulo, String contrasena) {
        conexion.ejecutar(queryIngresoFila(titulo, contrasena));
    }

    /**
     * Permite adaptar una palabra para retirar sus espacios en blanco y demás carácteres 
     * incompatbiles y poderlo ingresar al MySQL sin problemas.
     * @param palabraModificar String con la palabra a modificar.
     * @return String con una palabra compatible para MySQL.
     */
    private String adaptarParaBD(String palabraModificar) {
        String palabraAdaptada;
        palabraAdaptada = palabraModificar.toLowerCase();
        palabraAdaptada = palabraAdaptada.replaceAll(" ", "_");
        palabraAdaptada = palabraAdaptada.replaceAll("ñ", "nh");
        palabraAdaptada = palabraAdaptada.replaceAll("[^a-zA-Z 0-9]+", "");
        return palabraAdaptada;
    }

    /**
     * Permite adaptar una palabra proveniente de la base de datos a una con 
     * un formato un tanto más familiar para el usuario.
     * @param palabraModificar String con la palabra a modificar.
     * @return String con una palabra de aspecto más atractivo para el usuario.
     */
    private String adaptarParaUsuario(String palabraModificar) {
        String palabraAdaptada;
        palabraAdaptada = palabraModificar.replaceAll("_", " ");
        palabraAdaptada = palabraAdaptada.replaceAll("nh", "ñ");
        palabraAdaptada = palabraAdaptada.toUpperCase();
        return palabraAdaptada;
    }

    /**
     * Elabora el query para ingresar una nueva fila a la tabla correspondiente a 
     * esta categoría en MySQL.
     * @param titulo String con el titulo del nuevo elemento. 
     * @param contrasena String con la contraseña correspondiente al nuevo elemento.
     * @return String que contiene el query adecuado para ingresar una fila en MySQL.
     */
    private String queryIngresoFila(String titulo, String contrasena) {
        String query = "INSERT INTO " + tituloBD + "(titulo, contrasenha)"
                + " VALUES (\"" + titulo + "\", \"" + contrasena + "\")";
        return query;
    }

    /**
     * Permite cambiar un elemento en esta categoría.
     * @param datoNuevo String con el nuevo dato a ingresar en un campo de cierto elemento.
     * @param id Int con el número de identificación del elemento en la base de datos.
     * @param columna Int con el número de columna, o campo, en el cual se encuentra el dato a modificar.
     */
    public void cambioElemento(String datoNuevo, int id, int columna) {
        String nombreCampo = camposBD.get(columna);
        String query = "UPDATE " + tituloBD + " SET " + nombreCampo + " = \"" + datoNuevo + "\" WHERE id = " + id;
        conexion.ejecutar(query);
    }

    /**
     * Devuelve el título de la categoría en la base de datos.
     * @return String con el título de la categoría en la base de datos.
     */
    public String getTituloBD() {
        return tituloBD;
    }

    /**
     * Devuelve el atributo fine, que indica si la tabla ha sido creada
     * correctamente.
     * @return boolean true si la tabla fue creada correctamente; false en caso contrario.
     */
    public boolean isFine() {
        return fine;
    }
}